package com.plat.api.aop;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.plat.api.anonation.NoToken;
import com.plat.api.common.RespCode;
import com.plat.api.dao.api.TokenDao;
import com.plat.api.entity.api.TokenEntity;
import com.plat.api.exception.PlatException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.beetl.sql.core.query.LambdaQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * author ss
 * createTime 2020/5/8
 * package ${com.example.demo.aop}
 ***/
@Component
@Aspect
@Slf4j
public class TokenAspect {
    @Autowired
    private HttpServletRequest request; //这里可以获取到request
    @Autowired
    private TokenDao tokenDao;

    @Pointcut("@within(com.plat.api.anonation.Token)||@annotation(com.plat.api.anonation.NoToken)||@within(com.plat.api.anonation.NoToken))")
    public void before() {
    }

    @Before("before()")
    public void token(JoinPoint joinPoint) throws PlatException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 打印请求内容
        log.info("===============请求内容===============");
        log.info("请求地址:" + request.getRequestURL().toString());
        log.info("请求方式:" + request.getMethod());
        log.info("请求类方法:" + joinPoint.getSignature());
        log.info("请求类方法参数:" + Arrays.toString(joinPoint.getArgs()));
        log.info("请求时间:" + DateUtil.format(new Date(), "yyyy-MM-dd hh:mm:ss"));
        String jsonString = Arrays.toString(joinPoint.getArgs());
        JSONArray json = JSONArray.parseArray(jsonString);
        Object[] args = joinPoint.getArgs();
        Class<?>[] argTypes = new Class[joinPoint.getArgs().length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }
        Method method = null;
        try {
            method = joinPoint.getTarget().getClass()
                    .getMethod(joinPoint.getSignature().getName(), argTypes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        NoToken ma = method.getAnnotation(NoToken.class);
        if (ma == null) {
            String token = json.getJSONObject(0).getJSONObject("head").getString("token");
            LambdaQuery<TokenEntity> query = tokenDao.getSQLManager().lambdaQuery(TokenEntity.class);
            TokenEntity tokenEntity = query.andEq("token", token).single();
            if (tokenEntity == null) {
                throw new PlatException(RespCode.FAIL.getCode(), "token不存在请重新登录");
            }
            if (tokenEntity.getExpireTime().getTime() < new Date().getTime()) {
                throw new PlatException(RespCode.FAIL.getCode(), "token过期请重新登录");
            }
        }


    }

    public String getParam(JoinPoint joinPoint) {
        Object result = null;

        Signature signature = joinPoint.getSignature();
        // 方法名
        String methodName = signature.getName();
        // 类名
        String serviceName = signature.getDeclaringTypeName();

        // 参数名数组
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
        // 构造参数组集合
        List<Object> argList = new ArrayList<>();
        for (Object arg : joinPoint.getArgs()) {
            // request/response无法使用toJSON
            if (arg instanceof HttpServletRequest) {
                argList.add("request");
            } else if (arg instanceof HttpServletResponse) {
                argList.add("response");
            } else {
                argList.add(JSON.toJSON(arg));
            }
        }
        try {
            log.info("{} -> 方法({}) -> 参数:{} - {}", serviceName, methodName, JSON.toJSON(parameterNames), JSON.toJSON(argList));
        } catch (Exception e) {
            log.error("参数获取失败: {}", e.getMessage());
        }
//        result = joinPoint.proceed();
        return null;
    }
}
